package com.pg.agent.engine.service.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.pg.agent.engine.client.bo.ComponentAllInParamBO;
import com.pg.agent.engine.client.bo.ComponentInParamBO;
import com.pg.agent.engine.client.bo.CurrentComponentBO;
import com.pg.agent.engine.client.bo.InterfaceBO;
import com.pg.agent.engine.client.common.enums.ComponentArgGetWayEnum;
import com.pg.agent.engine.client.common.enums.ComponentTypeEnum;
import com.pg.agent.engine.client.common.enums.StreamOutTypeEnum;
import com.pg.agent.engine.client.component.APIComponent;
import com.pg.agent.engine.client.component.AgentComponentLLM;
import com.pg.agent.engine.client.component.SystemFunc;
import com.pg.agent.engine.client.message.InPutMessage;
import com.pg.agent.engine.client.message.OutPutMessage;
import com.pg.agent.engine.client.model.*;
import com.pg.agent.engine.client.model.action.Action;
import com.pg.agent.engine.client.model.agent.AIAgent;
import com.pg.agent.engine.client.model.agent.AgentActionBO;
import com.pg.agent.engine.client.model.agent.AgentCompileResult;
import com.pg.agent.engine.client.model.agent.ComponentParam;
import com.pg.agent.engine.client.model.environment.AIEnvironment;
import com.pg.agent.engine.client.model.llm.CallLog;
import com.pg.agent.engine.client.model.llm.ComponentLLM;
import com.pg.agent.engine.client.model.sop.Memory;
import com.pg.agent.engine.client.model.state.AIState;
import com.pg.agent.engine.client.vo.ComponentInParamType;
import com.pg.agent.engine.client.vo.HttpParam;
import com.pg.agent.engine.service.OutParamContext;
import com.pg.agent.engine.service.service.AIAgentService;
import com.pg.agent.engine.service.service.AIEnvironmentService;
import com.pg.agent.engine.service.utils.*;
import com.pg.base.exception.BizException;
import com.pg.base.util.PgHttpUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.net.ConnectException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;

/**
 * Ai agent执行类
 * @author huhuaping
 * @date 2023/11/14 18:15
 */
@Service
@Slf4j
public class AIAgentServiceImpl implements AIAgentService {

    @Resource
    private AIEnvironmentService aiEnvironmentService;



    @Override
    public AIAgent initUserAgent(String userName) {
        AIAgent aiAgent = new AIAgent();
        aiAgent.setName(Optional.ofNullable(userName).orElse("User"));
        aiAgent.setStyle("");
        aiAgent.setRole("User");
        aiAgent.setUser(true);
        return aiAgent;
    }

    @Override
    public Action step(AgentActionBO agentActionBO) {

        // 首先根据当前环境更新信息
        AIAgent agent = agentActionBO.getAgent();
        InPutMessage message = agentActionBO.getMessage();
        agent.setCurrentRole(agent.getRole());
        boolean begin = message.getState().isBegin();
        message.getState().setBegin(false);

        String result = "";
        ComResponse comResponse = new ComResponse();
        // 封装Action执行对象
        Action action = new Action();
        CallLog callLog = new CallLog();

        if (agent.isUser()) {
            // 如果是用户输入内容，直接返回
            result = agent.getName() + ":" + agentActionBO.getInput();
        } else {
            // 判断environment长记忆，如果大于1，则需要监控，并组装agent本身记忆添加到长记忆当中去
            if (CollectionUtil.isNotEmpty(message.getEnvironment().getShareMemory().getLongMemory())) {
                if (agent.getLongTermMemory() == null) {
                    agent.setLongTermMemory(new ArrayList<>());
                }
                if (!agentActionBO.isRepeat()) {
                    Memory observe = observe(agent, message);
                    agent.setObserveMemory(observe);
                }
            }
            // 判断是否首次执行，如果是首次，直接返回JSON定义的回复。

            //执行智能体agent操作方法
            AgentCompileResult agentCompileResult = act(agentActionBO);
//            Map<String, AtomicBoolean> atomicIntegerMap = SessionConnectManager.getInstance().getStoryMap();
//            AtomicBoolean atomicBoolean = atomicIntegerMap.get(agentActionBO.getMessage().getSessionId());
//            if (atomicBoolean != null && !atomicBoolean.get()) {
//                SessionConnectManager.getInstance().addStopSessionId(agentActionBO.getMessage().getSessionId());
//                log.info("流程中断");
//                return null;
//            }
            if (ObjectUtil.isNotEmpty(agentCompileResult.getComponentUserInPutParam()) && agentCompileResult.getComponentUserInPutParam().size() > 0) {
                callLog.setComponentUserInPutParam(agentCompileResult.getComponentUserInPutParam());
                action.setCallLog(callLog);
                return action;
            }
            result = agentCompileResult.getResponse();
            comResponse = agentCompileResult.getComResponse();
            callLog = agentCompileResult.getCallLog();
            action.setAgentResult(agentCompileResult.getAgentResult());
        }

        agent.setFirstSpeak(false);
        callLog.setResponse(result);
        action.setCallLog(callLog);
        action.setResponse(Collections.singletonList(result));
        action.setResDict(comResponse);
        action.setRole(agent.getCurrentRole());
        action.setName(agent.getName());
        action.setUser(agent.isUser());
        return action;
    }



    @Override
    public AgentCompileResult act(AgentActionBO agentActionBO) {
        AIAgent agent = agentActionBO.getAgent();
        //获取当前对话长记忆
        List<Memory> chatHistory = new ArrayList<>();
        if (agent.getObserveMemory() != null) {
            chatHistory.add(agent.getObserveMemory());
        }
        //收集组装数据
        CallLog callLog = new CallLog(agent.getName(), "Agent调用");

        AgentCompileResult agentCompileResult = this.compile(agentActionBO);


        if (ObjectUtil.isNotEmpty(agentCompileResult.getComponentUserInPutParam()) && agentCompileResult.getComponentUserInPutParam().size() > 0) {
            agentCompileResult.setCallLog(callLog);
            return agentCompileResult;
        }
        //调用大模型
        Map<Long, JSONObject> componentResult = agentCompileResult.getComponentResult();
        log.info("componentResult:{}", JSONObject.toJSONString(componentResult));

        //是否需要调用大模型标记
        boolean flag = true;
        Map<Long, APIComponent> apiComponentMap = agent.getApiComponentList().stream().collect(Collectors.toMap(APIComponent::getId, java.util.function.Function.identity(), (a, b) -> a));

        StringBuilder stringBuilder = new StringBuilder();
        String agentResult = "";
        for (Map.Entry<Long, JSONObject> entity : componentResult.entrySet()) {
            Long key = entity.getKey();
            JSONObject jsonObject = entity.getValue();
            APIComponent apiComponent = apiComponentMap.get(key);
            if (apiComponent.getComponentLLM() != null) {
                ComponentLLM llm = apiComponent.getComponentLLM().getComponentLLM();
                String content = jsonObject.getString("rootdatacontent");
                if (llm != null && llm.getType() == 0) {
                    agentResult = agentResult + content;
                }
                flag = false;
                if (callLog.getResponse() == null) {
                    callLog.setResponse(content);
                } else {
                    callLog.setResponse(callLog.getResponse() + content);
                }
                continue;
            }

            List<ComponentOutParam> list = JSONObject.parseArray(apiComponent.getOutParam(), ComponentOutParam.class);
            List<ComponentOutParam> allList = new ArrayList<>();
            JSONUtils.getAllComponentOutParam(list, allList, "");

            for (ComponentOutParam outParam : allList) {
                Integer outType = outParam.getOutType() == null ? 0 : outParam.getOutType();
                String paramCode = outParam.getNewParamCode();
                if (outType == 0) {
                    continue;
                }
                if (outType == 1) {
                    int type = apiComponent.getType();
                    String content = jsonObject.getString(paramCode);
                    if (type != 1) {
                        agentResult = agentResult + content;
                    }
                    if (StringUtils.isNotEmpty(content)) {
                        flag = false;
                        if (callLog.getResponse() == null) {
                            callLog.setResponse(content);
                        } else {
                            callLog.setResponse(callLog.getResponse() + content);
                        }
                    }
                } else if (outType == 2) {
                    Object object = jsonObject.get(paramCode);
                    if (object != null) {
                        if (object instanceof JSONArray) {
                            callLog.getImageList().addAll(jsonObject.getJSONArray(paramCode).toJavaList(String.class));
                        } else {
                            callLog.getImageList().add(jsonObject.getString(paramCode));
                        }
                    }
                } else if (outType == 3) {
                    Object object = jsonObject.get(paramCode);
                    if (object != null) {
                        if (object instanceof JSONArray) {
                            callLog.getLabelList().addAll(jsonObject.getJSONArray(paramCode).toJavaList(String.class));
                        } else {
                            callLog.getLabelList().add(jsonObject.getString(paramCode));
                        }
                    }
                }
            }
        }

        //解析Agent的数据返回
        String result = agent.getResponse();
        for (ComponentParam componentParam : agent.getComponentParamList()) {
            Long componentId = componentParam.getComponentId();
            String paramCode = componentParam.getParamCode();
            JSONObject jsonObject = componentResult.get(componentId);
            if (jsonObject == null) {
                result = result.replace("{comp-" + componentId + "-" + paramCode + "}", "null");
            } else {
                try {
                    result = result.replace("{comp-" + componentId + "-" + paramCode + "}", jsonObject.get(paramCode) == null ? "null" : jsonObject.get(paramCode).toString());
                } catch (Exception e) {
                    log.info("解析异常：{}", e.getMessage());
                }
            }
        }
        callLog.setAgentResponse(result);

        if (agentActionBO.isRepeat()) {
            flag = false;
        }

        Map<String, AtomicBoolean> atomicIntegerMap = SessionConnectManager.getInstance().getStoryMap();
        AtomicBoolean atomicBoolean = atomicIntegerMap.get(agentActionBO.getMessage().getSessionId());
        if (atomicBoolean != null && !atomicBoolean.get()) {
            SessionConnectManager.getInstance().addStopSessionId(agentActionBO.getMessage().getSessionId());
            log.info("流程中断");
            agentCompileResult.setResponse(callLog.getResponse());
            agentCompileResult.setAgentResult(agentResult);
            agentCompileResult.setAgentResponse(result);
            agentCompileResult.setCallLog(callLog);
            return agentCompileResult;
        }

        //调用大模型
        if (agent.getComLLM() != null && false) {
            if (flag) {
                ComponentLLMUtil.getStreamCall(callLog, agent.getComLLM(), agentActionBO.getMessage(), chatHistory, agentCompileResult.getSystemPrompt(),
                        stringBuilder.toString() + agentCompileResult.getLastPrompt(), agentActionBO.getResponse(), agentActionBO.getOutMessage());
                if (agent.getComLLM().getType() != null && agent.getComLLM().getType() == 0) {
                    agentResult = callLog.getResponse();
                }
            }
        }
        agentResult="很开心来到这里";

        agentCompileResult.setResponse(callLog.getResponse());
        agentCompileResult.setAgentResult(agentResult);
        agentCompileResult.setAgentResponse(result);
        agentCompileResult.setCallLog(callLog);

        return agentCompileResult;
    }

    @Override
    public AgentCompileResult compile(AgentActionBO agentActionBO) {
        AIAgent agent = agentActionBO.getAgent();
        //获取当前状态下角色对应的组件。
        List<APIComponent> apiComponents = agent.getApiComponentList();

        // 大模型场景说明模板
        String systemPrompt = agent.getPrompt();
        // 大模型返回结果模板
        StringBuilder lastPrompt = new StringBuilder();
        ComResponse resDict = new ComResponse();
        Map<Long, JSONObject> preResult = new LinkedHashMap<>();
        InPutMessage message = agentActionBO.getMessage();
        OutPutMessage outMessage = agentActionBO.getOutMessage();
        String input = agentActionBO.getInput();
        boolean inParamFlag = agentActionBO.isInParamFlag();
        HttpServletResponse response = agentActionBO.getResponse();

        if (apiComponents != null && apiComponents.size() > 0) {
            for (APIComponent apiComponent : apiComponents) {
                Map<String, AtomicBoolean> atomicIntegerMap = SessionConnectManager.getInstance().getStoryMap();
                AtomicBoolean atomicBoolean = atomicIntegerMap.get(message.getSessionId());
                if (atomicBoolean != null && !atomicBoolean.get()) {
                    SessionConnectManager.getInstance().addStopSessionId(message.getSessionId());
                    log.info("流程中断");
                    break;
                }
                ComponentAllInParamBO componentAllInParamBO = null;
                if (!agentActionBO.isRepeat()) {
                    if (inParamFlag && agent.getExecComList().contains(apiComponent.getId())) {
                        preResult.put(apiComponent.getId(), agent.getComponentResult().get(apiComponent.getId()));
                        continue;
                    }
                    if (apiComponent.getComponentLLM() != null) {
                        JSONObject result = executeComponentLLM(agent, apiComponent, message, agentActionBO.getResponse(), outMessage, input, preResult);

                        JSONObject jsonObject = new JSONObject();
                        jsonObject.put("rootdatacontent", result.getJSONObject("data").get("content"));
                        jsonObject.put("root", result.get("data"));
                        preResult.put(apiComponent.getId(), jsonObject);
                        agent.setComponentResult(preResult);
                        continue;
                    }
                    componentAllInParamBO = getComponentInParam(apiComponent, agent, agentActionBO.getInputParamParam(), preResult, input, message, inParamFlag);
                    //执行组件
                    if (componentAllInParamBO.getComponentInParamList().size() > 0) {
                        AgentCompileResult agentCompileResult = new AgentCompileResult();
                        agentCompileResult.setComponentUserInPutParam(componentAllInParamBO.getComponentInParamList());
                        CurrentComponentBO currentComponentBO = new CurrentComponentBO();
                        currentComponentBO.setComponentId(apiComponent.getId());
                        currentComponentBO.setArgument(componentAllInParamBO.getInParamMap());
                        agent.setCurrentComponent(currentComponentBO);
                        return agentCompileResult;
                    }
                } else {
                    boolean componentRepeat = apiComponent.isRepeat();
                    if (!componentRepeat) {
                        continue;
                    }
                    componentAllInParamBO = new ComponentAllInParamBO();
                    componentAllInParamBO.setInParamMap(agent.getExecComponentInParam().get(apiComponent.getId()));
                }

                Map<String, JSONObject> result = executeComponent(agent, apiComponent, message, response, outMessage, componentAllInParamBO);

                List<ComponentOutParam> list = JSONObject.parseArray(apiComponent.getOutParam(), ComponentOutParam.class);
                List<ComponentOutParam> allList = new ArrayList<>();
                JSONUtils.getAllComponentOutParam(list, allList, "");
                Map<Long, Map<String, Object>> apiFlattMap = new HashMap<>();
                JSONObject jsonObject = new JSONObject();
                for (ComponentOutParam outParam : allList) {
                    Long apiId = outParam.getId();
                    JSONObject apiResult = result.get(String.valueOf(apiId));
                    Map<String, Object> flattenedMap = new LinkedHashMap<>();
                    if (!apiFlattMap.containsKey(apiId)) {
                        JSONUtils.flattenJson("root", apiResult, flattenedMap);
                        flattenedMap.put("root", apiResult);
                        apiFlattMap.put(apiId, flattenedMap);
                    } else {
                        flattenedMap = apiFlattMap.get(apiId);
                    }
                    //数据扁平化
                    //前缀没有root,如果需要获取值，需要去除前缀root
                    jsonObject.put(outParam.getNewParamCode(), flattenedMap.get(outParam.getNewParamCode()));

                }
                if (apiComponent.getReturnType() != null && apiComponent.getReturnType() == 2) {
                    String agentResponse = agent.getResponse();
                    for (ComponentParam componentParam : agent.getComponentParamList()) {
                        Long componentId = componentParam.getComponentId();
                        String paramCode = componentParam.getParamCode();
                        if (componentId.longValue() == apiComponent.getId().longValue()) {

                            try {
                                agentResponse = agentResponse.replace("{" + componentId + "-" + paramCode + "}", jsonObject.get(paramCode) == null ? "null" : jsonObject.get(paramCode).toString());
                            } catch (Exception e) {
                                log.info("解析异常：{}", e.getMessage());
                            }
                        }
                    }
                    OutPutMessage outPutMessage = new OutPutMessage();
                    outPutMessage.setAgentResponse(agentResponse);
                    Utils.outputStreamResult(null, message.getMessageId(), false, outPutMessage, response);
                }

                preResult.put(apiComponent.getId(), jsonObject);
                agent.setComponentResult(preResult);
            }

        }

        // 替换提示模板
        lastPrompt = new StringBuilder(String.format(PromptConstant.AGENT_LAST_PROMPT, lastPrompt.toString(), agent.getName()));
        systemPrompt = String.format(PromptConstant.AGENT_SYSTEM_PROMPT, systemPrompt);
        AgentCompileResult agentCompileResult = new AgentCompileResult(lastPrompt.toString(), systemPrompt, resDict);
        agentCompileResult.setComponentResult(preResult);
        return agentCompileResult;

    }

    private JSONObject executeComponentLLM(AIAgent agent, APIComponent apiComponent, InPutMessage message, HttpServletResponse response, OutPutMessage outMessage, String input, Map<Long, JSONObject> preResult) {
        CallLog callLog = new CallLog(agent.getName() + "[" + apiComponent.getName() + "]", "组件执行");
        callLog.setCallStartTime(new Date());

        AgentComponentLLM agentComponentLLM = apiComponent.getComponentLLM();
        String prompt = agentComponentLLM.getPrompt();

        JSONObject userParam = message.getUserParam();
        JSONObject newUserParam = JSONObject.parseObject(JSONObject.toJSONString(userParam));
        Map<String, Object> flattenedMap = new LinkedHashMap<>();
        JSONUtils.flattenJson("", newUserParam, flattenedMap);

        Map<String, Object> systemParam = getSystemParam(message, input);
        List<String> systemParamList = agentComponentLLM.getSystemParam();
        List<String> customerParamList = agentComponentLLM.getCustomerParam();

        if (systemParamList != null) {
            //替换系统参数
            for (String paramCode : systemParamList) {
                Object object = systemParam.get(paramCode);
                String value = "";
                if (object != null) {
                    value = object.toString();
                }
                prompt = prompt.replace("{sys-" + paramCode + "}", value);
            }
        }
        //替换用户自定义参数
        if (customerParamList != null) {
            for (String paramCode : customerParamList) {
                Object object = flattenedMap.get(paramCode);
                String value = "";
                if (object != null) {
                    value = object.toString();
                }
                prompt = prompt.replace("{custom-" + paramCode + "}", value);
            }
        }

        Map<Long, List<String>> componentParam = agentComponentLLM.getComponentParam();
        if (componentParam != null) {
            for (Map.Entry<Long, List<String>> entry : componentParam.entrySet()) {
                Long key = entry.getKey();
                JSONObject jsonObject = preResult.get(key);
                List<String> list = entry.getValue();
                for (String paramCode : list) {
                    String value = "";
                    if (jsonObject != null) {
                        value = jsonObject.get(paramCode.replace("-", "")) == null ? "" : jsonObject.get(paramCode.replace("-", "")).toString();
                    }
                    prompt = prompt.replace("{comp-" + key + "-" + paramCode + "}", value);
                }
            }
        }


        Long apiId = apiComponent.getInterfaceBOList().get(0).getInterfaceId();
        ComponentLLMUtil.callAgentComponent(callLog, outMessage, agentComponentLLM, message, prompt, "你是一个工具助手", response);
        Map<Long, List<InParam>> inParamMap = new HashMap<>();
        inParamMap.put(apiId, JSONObject.parseArray(callLog.getArguments(), InParam.class));
        agent.getExecComponentInParam().put(apiComponent.getId(), inParamMap);
        JSONObject jsonObject = new JSONObject();
        JSONObject data = new JSONObject();
        data.put("content", callLog.getResponse());
        jsonObject.put("data", data);
        jsonObject.put("content", callLog.getResponse());
        return jsonObject;
    }

    @Override
    public void updateMemory(InPutMessage message, Memory memory) {
        AIAgent agent = message.getAgent();

        // 添加agent长记忆。角色为大模型助手assistant
        agent.getLongTermMemory().add(new Memory(message.getExeId(), memory.getDataId(), "assistant", agent.getName(), memory.getContent()));

        AIEnvironment aiEnvironment = message.getEnvironment();
        Integer maxChatHistory = aiEnvironment.getConfig().getMaxChatHistory();

        //判断环境类型EnvironmentType，cooperative:在不同的状态之间共享信息;competive:不同状态之间没有信息共享
        int currentChatHistoryIdx = "competive".equals(aiEnvironment.getEnvironmentType()) ? aiEnvironment.getCurrentChatHistoryIdx() : 0;

        // 截取当前状态下的记忆。
        List<Memory> currentLongTermMemory = aiEnvironment.getShareMemory().getLongMemory().subList(currentChatHistoryIdx, aiEnvironment.getShareMemory().getLongMemory().size());

        // 获取当前Agent 在当前状态下 最后一次说话的下标
        Integer lastConversationIdx = aiEnvironmentService.getAgentLastConversationIdx(agent, currentLongTermMemory);

        if (currentLongTermMemory.size() - lastConversationIdx >= maxChatHistory) {
            AIState currentState = message.getState();

            String conversations = aiEnvironmentService.getAgentNewMemory(currentLongTermMemory);
            // 总结模板
            String summaryPrompt = currentState.getSummaryPrompt();

            summaryPrompt = String.format(PromptConstant.AGENT_SUMMARY_SYSTEM_PROMPT, agent.getShortTermMemory(), summaryPrompt, conversations);

            //调用大模型
            CallLog callLog = new CallLog(agent.getName(), "Agent总结记忆");

            //ComponentLLMUtil.call(llmCallInfo, agent.getComLLM(), session, null, summaryPrompt, "");

            // 对总结的数据更新到agent端记忆中。
            agent.setShortTermMemory(callLog.getResponse());
        }
    }

    public String obtainEnvironmentPrompt(AIAgent agent, AIState state) {
        String environmentPrompt = state.getEnvironmentPrompt();
        if (agent.getParamMap() == null) {
            return environmentPrompt;
        }
        List<String> envParam = (List<String>) agent.getParamMap().get("env");

        if (envParam == null) {
            return environmentPrompt;
        }
        if (environmentPrompt != null && CollectionUtil.isNotEmpty(envParam)) {
            for (int i = 0; i < envParam.size(); i++) {
                environmentPrompt = environmentPrompt.replace("{" + i + "}", envParam.get(i));
            }
        }
        return environmentPrompt;
    }


    /**
     * 组装组件的入参数据
     * @param apiComponent
     * @param agent
     * @param userInput
     * @param preResult
     * @param input
     * @param message
     * @param inParamFlag
     * @return
     */
    ComponentAllInParamBO getComponentInParam(APIComponent apiComponent, AIAgent agent, Map<String, JSONObject> userInput, Map<Long, JSONObject> preResult,
                                              String input, InPutMessage message, boolean inParamFlag) {
        ComponentAllInParamBO componentAllInParamBO = new ComponentAllInParamBO();

        CurrentComponentBO currentComponentBO = agent.getCurrentComponent();
        //判断是否执行过一次获取参数的过程
        if (inParamFlag && currentComponentBO != null && currentComponentBO.getComponentId().longValue() == apiComponent.getId().longValue()) {
            componentAllInParamBO.setInParamMap(currentComponentBO.getArgument());
            componentAllInParamBO.setComponentInParamList(new ArrayList<>());
            for (Map.Entry<Long, List<InParam>> entry : componentAllInParamBO.getInParamMap().entrySet()) {
                List<InParam> value = entry.getValue();
                Long key = entry.getKey();
                if (userInput.containsKey(String.valueOf(key))) {
                    JSONObject userParam = userInput.get(String.valueOf(key));
                    ParamUtil.putParam(value,userParam);
                } else {
                    ParamUtil.putParam(value,userInput);
                }
            }
            return componentAllInParamBO;
        }
        String inParamStr = apiComponent.getInParam();

        List<ComponentInParam> componentInParamList = JSONObject.parseArray(inParamStr, ComponentInParam.class);

        List<ComponentInParam> type2 = new ArrayList<>();
        for (ComponentInParam component : componentInParamList) {
            if (component.getTypeList() != null && component.getTypeList().stream().anyMatch(p -> p.getType() == 2)) {
                type2.add(component);
            }
        }
        JSONObject argument = new JSONObject();
        if (type2.size() > 0) {
            // 大模型提取参数
            argument = llmExtractParm(apiComponent, agent, input, message, argument);
        }
        List<InterfaceBO> list = apiComponent.getInterfaceBOList();
        Map<Long, List<InParam>> jsonObjectMap = new HashMap<>();
        List<ComponentInParam> componentList = new ArrayList<>();
        for (InterfaceBO interfaceBO : list) {
            Long interfaceId = interfaceBO.getInterfaceId();
            List<ComponentInParam> interfaceParam = componentInParamList.stream().filter(e -> e.getId().longValue() == interfaceId.longValue()).collect(Collectors.toList());
            //获取每个API的入参数据
            ComponentInParamBO component = getInParam(userInput, preResult, input, message, argument, interfaceParam, inParamFlag);
            componentList.addAll(component.getComponentInParamList());
            jsonObjectMap.put(interfaceId, component.getInParamList());
            interfaceBO.setInParamList(component.getInParamList());

        }
        componentAllInParamBO.setComponentInParamList(componentList);
        componentAllInParamBO.setInParamMap(jsonObjectMap);

        return componentAllInParamBO;
    }

    private static JSONObject llmExtractParm(APIComponent apiComponent, AIAgent agent, String input, InPutMessage message, JSONObject argument) {
        Map<String, Property> properties = new HashMap<>();
        List<String> required = new ArrayList<>();
        packApiParam(apiComponent.getInParam(), required, properties);

        Parameters funParameters = new Parameters("object");
        funParameters.setProperties(properties);
        funParameters.setRequired(required);
        List<Function> functionList = new ArrayList<>();
        Function function = new Function();
        function.setName(apiComponent.getCode());
        function.setDescription(apiComponent.getDescription());
        function.setParameters(funParameters);
        functionList.add(function);

        List<Memory> memoryList = new ArrayList<>();
        Memory memory = new Memory();
        memory.setContent(input);
        memory.setSendName(agent.getName());
        memoryList.add(memory);

        String newSystemPrompt = "现在你是一个参数提取助手。" + "\n 组件描述：" + apiComponent.getDescription();
        String newLastPrompt = "提示从用户输入获取";

        String argumentStr = null;

        //收集组装数据
        CallLog callLog = new CallLog(agent.getName() + "[" + apiComponent.getName() + "]", "组件参数提取");
        ComponentLLMUtil.callBack(callLog, message.getSop().getComLLM(), message, memoryList, newSystemPrompt, newLastPrompt, functionList);
        if (callLog.getArguments() != null) {
            argumentStr = callLog.getArguments();
            log.info("argumentStr:{}", argumentStr);
        }

        if (argumentStr != null) {
            argument = JSONObject.parseObject(argumentStr);
        }
        return argument;
    }


    /**
     * 执行组件
     */
    private Map<String, JSONObject> executeComponent(AIAgent agent, APIComponent apiComponent, InPutMessage message,
                                                     HttpServletResponse response, OutPutMessage outMessage, ComponentAllInParamBO component) {

        CallLog callLog = new CallLog(agent.getName() + "[" + apiComponent.getName() + "]", "组件执行");
        callLog.setCallStartTime(new Date());
        String chainName = null;
        String resultMessage = "";
        try {
            // 系统函数
            if (ComponentTypeEnum.SYS_FUN.getValue().equals(apiComponent.getConfigureType())) {
                SystemFunc systemFunc = apiComponent.getSystemFunc();
                String methodName = systemFunc.getMethodName();
                JSONObject result = null;
                OutParamContext outParamContext = new OutParamContext();
                outParamContext.setCreateTime(new Date());
                if ("getHistory".equals(methodName)) {

                    List<InParam> inParamList = component.getInParamMap().get(apiComponent.getSystemFunc().getId());
                    Integer historySize = ParamUtil.getInteger(inParamList, "historySize");
                    result = getHistory(message,historySize );
                    outParamContext.getMap().put(String.valueOf(apiComponent.getSystemFunc().getId()), result);
                    agent.getExecComList().add(apiComponent.getId());
                    return outParamContext.getMap();
                }
//            String className = systemFunc.getPackageName() + systemFunc.getClassName();
//            // 加载该类
//            Class<?> clazz = null;
//            try {
//                clazz = Class.forName(className);
//                // 创建对象实例（如果有构造函数）
//                Object obj = null;
//                if (clazz != null && !Modifier.isAbstract(clazz.getModifiers())) {
//                    Constructor<?> constructor = clazz.getConstructor();
//                    obj = constructor.newInstance();
//                    Method method = ReflectUtil.getMethod(obj.getClass(), methodName);
//
//                    // 传入参数值进行方法调用
//                }
//            } catch (Exception e) {
//                throw new RuntimeException(e);
//            }
            } else {
                List<InterfaceBO> list = apiComponent.getInterfaceBOList();
                //保存执行每个API的结果
                OutParamContext outParamContext = new OutParamContext();
                chainName = String.valueOf(System.currentTimeMillis());
                outParamContext.setChainName(chainName);
                outParamContext.setCreateTime(new Date());

                Map<String, InterfaceBO> inParam = list.stream().collect(Collectors.toMap(e -> String.valueOf(e.getInterfaceId()), e -> e, (a, b) -> a));
                Map<Long, List<InParam>> inParamMap = list.stream().collect(Collectors.toMap(e -> e.getInterfaceId(), e -> e.getInParamList(), (a, b) -> a));
                if (agent.getExecComponentInParam() == null) {
                    agent.setExecComponentInParam(new HashMap<>());
                }
                agent.getExecComponentInParam().put(apiComponent.getId(), inParamMap);
                InterfaceBO interfaceBO = list.get(0);
                List<InParam> inParamList = interfaceBO.getInParamList();
                HttpParam httpParam = HttpParam.instance("POST",inParamList);
                log.info("参数入参：{}", JSONObject.toJSONString(httpParam));
                callLog.setArguments(JSONObject.toJSONString(inParamList));
                callLog.addToLogInfo("请求路径", interfaceBO.getUrl());
                callLog.addToLogInfo("请求参数", JSONObject.toJSONString(inParamList));

                if (StreamOutTypeEnum.YES.getValue().equals(apiComponent.getType())) {
                    log.info("==========使用的是流式调用=============");


                    ComponentSSEListener sseListener = new ComponentSSEListener(httpParam, message, response, message.getMessageId(), outMessage, apiComponent);
                    //"http://server-decision-business-module.decision-itest.coding.clife.net:30000/education/chat"
                    JSONObject object = ExecuteSSEUtil.executeComponentSSE(interfaceBO.getUrl(), sseListener, httpParam);
                    resultMessage = JSONObject.toJSONString(object);
                    if (object.getInteger("code") != 0) {
                        throw new BizException(1000, resultMessage);
                    }
                    outParamContext.getMap().put(String.valueOf(interfaceBO.getInterfaceId()), object);
                } else {
                    resultMessage = HttpClientUtils.exeHttpCall(interfaceBO,httpParam);
                    outParamContext.getMap().put(String.valueOf(interfaceBO.getInterfaceId()), JSONObject.parseObject(resultMessage));
                }
                return outParamContext.getMap();
            }
        } catch (BizException bizException) {
            throw bizException;
        } catch (Exception e) {
            e.printStackTrace();
            resultMessage = "执行组件[" + apiComponent.getName() + "]失败,原因：" + e.getMessage();
            if (e instanceof ConnectException) {
                resultMessage += "连接失败," + e.getMessage();
            }
            throw new BizException(1000, resultMessage);
        } finally {
            message.addCallLog(callLog, resultMessage);
            agent.getExecComList().add(apiComponent.getId());
        }
        return null;
    }

    /**
     * 组装api的入参数据
     */
    private ComponentInParamBO getInParam(Map<String, JSONObject> userInput, Map<Long, JSONObject> preResult, String input,
                                          InPutMessage message, JSONObject argument, List<ComponentInParam> interfaceParam, boolean inParamFlag) {
        ComponentInParamBO componentInParamBO = new ComponentInParamBO();
        List<InParam> inParamList = new ArrayList<>();
        Map<String, Object> systemParam = getSystemParam(message, input);
        List<ComponentInParam> list = new ArrayList<>();
        for (ComponentInParam component : interfaceParam) {
            String paramCode = component.getParamCode();
            InParam inParam = BeanUtil.copyProperties(component, InParam.class);
            if ("history_qa".equals(paramCode)) {
                JSONObject param = new JSONObject();
                param.put("historySize", 10);
                List<JSONObject> history = (List<JSONObject>) getHistory(message, 10).get("list");
                inParam.setParamValue(history);
                inParamList.add(inParam);
                continue;
            }
            int size = ObjectUtil.isEmpty(component.getTypeList()) ? 0 : component.getTypeList().size();

            for (int i = 0; i <= size - 1; i++) {
                ComponentInParamType inParamType = component.getTypeList().get(i);
                int type = inParamType.getType();
                //类型 1.默认值 2.大模型提取，3.用户输入。4.组件输入。6.系统参数，7.自定义
                if (ComponentArgGetWayEnum.DEFAULT.getValue().equals(type)) {
                    if ("true".equals(inParamType.getDefaultValue()) || "false".equals(inParamType.getDefaultValue())) {
                        inParam.setParamValue(inParamType.getDefaultValue().equals("true"));
                    } else {
                        inParam.setParamValue(inParamType.getDefaultValue());
                    }
                    break;
                } else if (ComponentArgGetWayEnum.LLM_MODEL.getValue().equals(type)) {
                    if (!inParamList.contains(inParam)) {
                        if (argument.containsKey(paramCode)) {
                            inParam.setParamValue(argument.get(paramCode));
                            break;
                        }
                    }
                } else if (ComponentArgGetWayEnum.USER_INPUT.getValue().equals(type)) {
                    if (!inParamList.contains(inParam)) {
                        if (null != userInput && userInput.containsKey(paramCode)) {
                            inParam.setParamValue(userInput.get(paramCode));
                            break;
                        }
                    }
                } else if (ComponentArgGetWayEnum.COMPONENT_INPUT.getValue().equals(type)) {
                    if (!inParamList.contains(inParam)) {
                        Long componentId = inParamType.getComponentId();
                        JSONObject result = preResult.get(componentId);
                        if (result != null) {
                            Object object = result.get(inParamType.getParamCode().replace("-", ""));
                            if (object != null) {
                                inParam.setParamValue(result.get(inParamType.getParamCode().replace("-", "")));
                                break;
                            } else if (!inParamFlag) {
                                if (i < size - 1) {
                                    int newType = component.getTypeList().get(i + 1).getType();
                                    if (newType == 3) {
                                        JSONArray jsonArray = result.getJSONArray("rootdataconfirmInfo");
                                        if (jsonArray != null) {
                                            for (int j = 0; j < jsonArray.size(); j++) {
                                                JSONObject arrayValue = jsonArray.getJSONObject(j);
                                                String paramCodeValue = arrayValue.getString("confirmName");
                                                if (paramCode.equals(paramCodeValue)) {
                                                    String prefix = arrayValue.getString("prefix");
                                                    component.setPrefix(prefix);
                                                    component.setSelectValue(arrayValue.getJSONArray("confirmList"));
                                                    list.add(component);
                                                    break;
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                            break;
                        }
                    }
                } else if (ComponentArgGetWayEnum.SYS_PARAM.getValue().equals(type)) {
                    if (!inParamList.contains(inParam)) {
                        inParam.setParamValue(systemParam.get(inParamType.getParamCode()));
                        break;
                    }

                } else if (ComponentArgGetWayEnum.CUSTOM.getValue().equals(type)) {
                    if (!inParamList.contains(inParam)) {
                        JSONObject customerParam = message.getUserParam();
                        if (customerParam != null && !customerParam.isEmpty()) {
                            inParam.setParamValue(customerParam.get(inParamType.getParamCode()));
                            break;
                        }
                    }
                }else  if (ComponentArgGetWayEnum.TOKEN_PARAM.getValue().equals(type)){
                    InterfaceBO interfaceBO = inParamType.getInterfaceBO();
                    if (interfaceBO != null){
                        String token = "";
                        // TODO
                        //String token = JedisUtils.get(AgentConstant.TOKEN_PREFIX + interfaceBO.getInterfaceId());
                        if (token != null){
                            inParam.setParamValue(token);
                        }else {
                            String inParamStr = interfaceBO.getInParam();
                            List<ComponentInParam> componentInParamList = JSONObject.parseArray(inParamStr, ComponentInParam.class);

                            Long interfaceId = interfaceBO.getInterfaceId();
                            List<ComponentInParam> interfaceParam1 = componentInParamList.stream().filter(e -> e.getId().longValue() == interfaceId.longValue()).collect(Collectors.toList());
                            //获取每个API的入参数据
                            ComponentInParamBO componentInParamBO1 = getInParam(userInput, preResult, input, message, argument, interfaceParam1, inParamFlag);

                            HttpParam httpParam = HttpParam.instance("POST", componentInParamBO1.getInParamList());

                            String result = PgHttpUtil.postBody(interfaceBO.getUrl(),httpParam.getHeaders(),httpParam.getQuery(),httpParam.getPath(),JSON.toJSONString(httpParam.getBody()),100000);

                            cn.hutool.json.JSON JsonResult = JSONUtil.parse(result);

                            String newToken = JSONUtil.getByPath(JsonResult, interfaceBO.getTokenParam()).toString();
                            inParam.setParamValue(newToken);
                            //JedisUtils.set(AgentConstant.TOKEN_PREFIX + interfaceBO.getInterfaceId(),newToken,interfaceBO.getExpiryTime());
                        }
                    }
                }

            }
            inParamList.add(inParam);
        }
       //componentInParamBO.setJsonObject(inParamList);
        componentInParamBO.setInParamList(inParamList);
        componentInParamBO.setComponentInParamList(list);
        return componentInParamBO;
    }

    private static Map<String, Object> getSystemParam(InPutMessage message, String input) {
        Map<String, Object> map = new HashMap<>();
        map.put("query", input);
        map.put("user_id", message.getUserId());
        map.put("userId", message.getUserId());
        map.put("sopId", message.getSop());
        List<JSONObject> history = (List<JSONObject>) getHistory(message, 10).get("list");
        map.put("chat_history_message", history);

        String lastAnswer = "";
        if (history != null && history.size() > 0) {
            int size = history.size();
            for (int i = size - 1; i >= 0; i--) {
                JSONObject jsonObject = history.get(i);
                if (!jsonObject.getString("sendRole").equalsIgnoreCase("user")) {
                    lastAnswer = jsonObject.getString("content");
                    break;
                }
            }
        }
        map.put("lastAnswer", lastAnswer);
        map.put("imageList", message.getImageList());
        map.put("fileList", message.getFileList());
        return map;
    }

    public Memory observe(AIAgent agent, InPutMessage message) {
        return aiEnvironmentService.observe(message.getEnvironment(), agent, message);
    }

    @Override
    public void updateMemory(AIAgent agent, InPutMessage message, Memory memory) {

        // 添加agent长记忆。角色为大模型助手assistant
        agent.getLongTermMemory().add(new Memory(message.getExeId(), memory.getDataId(), "assistant", agent.getName(), memory.getContent()));

        AIEnvironment aiEnvironment = message.getEnvironment();
        Integer maxChatHistory = aiEnvironment.getConfig().getMaxChatHistory();

        //判断环境类型EnvironmentType，cooperative:在不同的状态之间共享信息;competive:不同状态之间没有信息共享
        int currentChatHistoryIdx = "competive".equals(aiEnvironment.getEnvironmentType()) ? aiEnvironment.getCurrentChatHistoryIdx() : 0;

        // 截取当前状态下的记忆。
        List<Memory> currentLongTermMemory = aiEnvironment.getShareMemory().getLongMemory().subList(currentChatHistoryIdx, aiEnvironment.getShareMemory().getLongMemory().size());

        // 获取当前Agent 在当前状态下 最后一次说话的下标
        Integer lastConversationIdx = aiEnvironmentService.getAgentLastConversationIdx(agent, currentLongTermMemory);

        if (currentLongTermMemory.size() - lastConversationIdx >= maxChatHistory) {
            AIState currentState1 = message.getState();

            String conversations = aiEnvironmentService.getAgentNewMemory(currentLongTermMemory);
            // 总结模板
            String summaryPrompt = currentState1.getSummaryPrompt();

            summaryPrompt = String.format(PromptConstant.AGENT_SUMMARY_SYSTEM_PROMPT, agent.getShortTermMemory(), summaryPrompt, conversations);

            //调用大模型
            CallLog callLog = new CallLog(agent.getName(), "Agent总结记忆");

            ComponentLLMUtil.call(callLog, agent.getComLLM(), message, null, summaryPrompt, "");

            // 对总结的数据更新到agent端记忆中。
            agent.setShortTermMemory(callLog.getResponse());
        }
    }


    private static void packApiParam(String inParam, List<String> required, Map<String, Property> properties) {
        if (StringUtils.isNotEmpty(inParam)) {

            JSONArray jsonArray = JSON.parseArray(inParam);

            for (int i = 0; i < jsonArray.size(); i++) {
                JSONObject jsonObject = jsonArray.getJSONObject(i);
                if (jsonObject.containsKey("paramCode")) {
                    String paramCode = jsonObject.getString("paramCode");
                    String desc = jsonObject.getString("paramDesc");
                    Integer paramType = jsonObject.getInteger("paramType");
                    Integer require = jsonObject.getInteger("required");
                    if (ObjectUtil.equals(require,1)) {
                        required.add(paramCode);
                    }
                    properties.put(paramCode, new Property(paramType, desc));
                }
            }
        }
    }

    public static JSONObject getHistory(InPutMessage message, Integer size) {
        int historySize = Optional.ofNullable(size).orElse(10);

        List<Memory> oldMemoryList = message.getEnvironment().getShareMemory().getLongMemory();
        List<Memory> memoryList = new ArrayList<>(oldMemoryList);
//        String beginQuery = null;
//        if(message.getSop().getStates()==null){
//            beginQuery = message.getSop().getStates().get(message.getSop().getRoot()).getBeginQuery();
//        }
//        if (memoryList.size() > 0 && ObjectUtil.isNotEmpty(beginQuery)) {
//            memoryList.remove(0);
//        }
        List<Memory> subMemoryList = memoryList;
        if (memoryList.size() > historySize) {
            subMemoryList = memoryList.subList(memoryList.size() - historySize, memoryList.size() - 1);
        }
        List<JSONObject> list = new ArrayList<>();
        for (Memory memory : subMemoryList) {
            JSONObject jsonObject = new JSONObject();
            if (memory.getSendRole() == null) {
                jsonObject.put("sendRole", memory.getSendName());
            } else if (memory.getSendRole().equalsIgnoreCase("user")) {
                jsonObject.put("sendRole", "user");
            } else {
                jsonObject.put("sendRole", memory.getSendRole());
            }
            jsonObject.put("sendName", memory.getSendName());
            jsonObject.put("content", memory.getContent());
            list.add(jsonObject);
        }
        JSONObject result = new JSONObject();
        result.put("list", list);
        return result;
    }
}
